home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint99s / debug.c < prev    next >
C/C++ Source or Header  |  1993-01-13  |  13KB  |  614 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* MiNT debugging output routines */
  8. /* also, ksprintf is put here, for lack of any better place to put it */
  9.  
  10. #include "mint.h"
  11. #include <stdarg.h>
  12.  
  13. static void VDEBUGOUT P_((int, const char *, va_list));
  14.  
  15. /*
  16.  * ksprintf implements a very crude sprintf() function that provides only
  17.  * what MiNT needs...
  18.  *
  19.  * NOTE: this sprintf probably doesn't conform to any standard at
  20.  * all. It's only use in life is that it won't overflow fixed
  21.  * size buffers (i.e. it won't try to write more than SPRINTF_MAX
  22.  * characters into a string)
  23.  */
  24.  
  25. static int
  26. PUTC(char *p, int c, int *cnt, int width) {
  27.     int put = 1;
  28.  
  29.     if (*cnt <= 0) return 0;
  30.     *p++ = c;
  31.     *cnt -= 1;
  32.     while (*cnt > 0 && --width > 0) {
  33.         *p++ = ' ';
  34.         *cnt -= 1;
  35.         put++;
  36.     }
  37.     return put;
  38. }
  39.  
  40. static int
  41. PUTS(char *p, const char *s, int *cnt, int width) {
  42.     int put = 0;
  43.  
  44.     if (s == 0) s = "(null)";
  45.  
  46.     while (*cnt > 0 && *s) {
  47.         *p++ = *s++;
  48.         put++;
  49.         *cnt -= 1;
  50.         width--;
  51.     }
  52.     while (width-- > 0 && *cnt > 0) {
  53.         *p++ = ' ';
  54.         put++;
  55.         *cnt -= 1;
  56.     }
  57.     return put;
  58. }
  59.  
  60. static int
  61. PUTL(char *p, unsigned long u, int base, int *cnt, int width, int fill_char)
  62. {
  63.     int put = 0;
  64.     static char obuf[32];
  65.     char *t;
  66.  
  67.     t = obuf;
  68.  
  69.     do {
  70.         *t++ = "0123456789ABCDEF"[u % base];
  71.         u /= base;
  72.         width--;
  73.     } while (u > 0);
  74.  
  75.     while (width-- > 0 && *cnt > 0) {
  76.         *p++ = fill_char;
  77.         put++;
  78.         *cnt -= 1;
  79.     }
  80.     while (*cnt > 0 && t != obuf) {
  81.         *p++ = *--t;
  82.         put++;
  83.         *cnt -= 1;
  84.     }
  85.     return put;
  86. }
  87.  
  88. int
  89. vksprintf(char *buf, const char *fmt, va_list args)
  90. {
  91.     char *p = buf, c, fill_char;
  92.     char *s_arg;
  93.     int i_arg;
  94.     long l_arg;
  95.     int cnt;
  96.     int width, long_flag;
  97.  
  98.     cnt = SPRINTF_MAX - 1;
  99.     while( (c = *fmt++) != 0 ) {
  100.         if (c != '%') {
  101.             p += PUTC(p, c, &cnt, 1);
  102.             continue;
  103.         }
  104.         c = *fmt++;
  105.         width = 0;
  106.         long_flag = 0;
  107.         fill_char = ' ';
  108.         if (c == '0') fill_char = '0';
  109.         while (c && isdigit(c)) {
  110.             width = 10*width + (c-'0');
  111.             c = *fmt++;
  112.         }
  113.         if (c == 'l' || c == 'L') {
  114.             long_flag = 1;
  115.             c = *fmt++;
  116.         }
  117.         if (!c) break;
  118.  
  119.         switch (c) {
  120.         case '%':
  121.             p += PUTC(p, c, &cnt, width);
  122.             break;
  123.         case 'c':
  124.             i_arg = va_arg(args, int);
  125.             p += PUTC(p, i_arg, &cnt, width);
  126.             break;
  127.         case 's':
  128.             s_arg = va_arg(args, char *);
  129.             p += PUTS(p, s_arg, &cnt, width);
  130.             break;
  131.         case 'd':
  132.             if (long_flag) {
  133.                 l_arg = va_arg(args, long);
  134.             } else {
  135.                 l_arg = va_arg(args, int);
  136.             }
  137.             if (l_arg < 0) {
  138.                 p += PUTC(p, '-', &cnt, 1);
  139.                 width--;
  140.                 l_arg = -l_arg;
  141.             }
  142.             p += PUTL(p, l_arg, 10, &cnt, width, fill_char);
  143.             break;
  144.         case 'o':
  145.             if (long_flag) {
  146.                 l_arg = va_arg(args, long);
  147.             } else {
  148.                 l_arg = va_arg(args, unsigned int);
  149.             }
  150.             p += PUTL(p, l_arg, 8, &cnt, width, fill_char);
  151.             break;
  152.         case 'x':
  153.             if (long_flag) {
  154.                 l_arg = va_arg(args, long);
  155.             } else {
  156.                 l_arg = va_arg(args, unsigned int);
  157.             }
  158.             p += PUTL(p, l_arg, 16, &cnt, width, fill_char);
  159.             break;
  160.         case 'u':
  161.             if (long_flag) {
  162.                 l_arg = va_arg(args, long);
  163.             } else {
  164.                 l_arg = va_arg(args, unsigned int);
  165.             }
  166.             p += PUTL(p, l_arg, 10, &cnt, width, fill_char);
  167.             break;
  168.  
  169.         }
  170.     }
  171.     *p = 0;
  172.     return (int)(p - buf);
  173. }
  174.  
  175. int ARGS_ON_STACK 
  176. ksprintf(char *buf, const char *fmt, ...)
  177. {
  178.     va_list args;
  179.     int foo;
  180.  
  181.     va_start(args, fmt);
  182.     foo = vksprintf(buf, fmt, args);    
  183.     va_end(args);
  184.     return foo;
  185. }
  186.  
  187. int debug_level = 1;    /* how much debugging info should we print? */
  188. int out_device = 2;    /* BIOS device to write errors to */
  189.  
  190. /*
  191.  * out_next[i] is the out_device value to use when the current
  192.  * device is i and the user hits F3.
  193.  * Cycle is CON -> PRN -> AUX -> MIDI -> 6 -> 7 -> 8 -> 9 -> CON
  194.  * (Note: BIOS devices 6-8 exist on Mega STe and TT, 9 on TT.)
  195.  *
  196.  * out_device and this table are exported to bios.c and used here in HALT().
  197.  */
  198.  
  199. /*            0  1  2  3  4  5  6  7  8  9 */
  200. char out_next[] = { 1, 3, 0, 6, 0, 0, 7, 8, 9, 2 };
  201.  
  202. /*
  203.  * debug log modes:
  204.  *
  205.  * 0: no logging.
  206.  * 1: log all messages, dump the log any time something happens at
  207.  *    a level that gets shown.  Thus, if you're at debug_level 2,
  208.  *    everything is logged, and if something at levels 1 or 2 happens,
  209.  *    the log is dumped.
  210.  *
  211.  * LB_LINE_LEN is 20 greater than SPRINTF_MAX because up to 20 bytes
  212.  * are prepended to the buffer string passed to ksprintf.
  213.  */
  214.  
  215. #define LBSIZE 50                /* number of lines */
  216. #define LB_LINE_LEN (SPRINTF_MAX+20)        /* width of a line */
  217. int debug_logging;
  218. int logptr;
  219. static char logbuf[LBSIZE][LB_LINE_LEN];
  220. static short logtime[LBSIZE];    /* low 16 bits of 200Hz: timestamp of msg */
  221.  
  222. /*
  223.  * Extra terse settings - don't even output ALERTs unless asked to.
  224.  *
  225.  * Things that happen in on an idle Desktop are at LOW_LEVEL:
  226.  * Psemaphore, Pmsg, Syield.
  227.  */
  228.  
  229. #define FORCE_LEVEL 0
  230. #define ALERT_LEVEL 1
  231. #define DEBUG_LEVEL 2
  232. #define TRACE_LEVEL 3
  233. #define LOW_LEVEL 4
  234.  
  235. /*
  236.  * The inner loop does this: at each newline, the keyboard is polled. If
  237.  * you've hit a key, then it's checked: if it's ctl-alt, do_func_key is
  238.  * called to do what it says, and that's that.  If not, then you pause the
  239.  * output.  If you now hit a ctl-alt key, it gets done and you're still
  240.  * paused.  Only hitting a non-ctl-alt key will get you out of the pause. 
  241.  * (And only a non-ctl-alt key got you into it, too!)
  242.  *
  243.  * When out_device isn't the screen, number keys give you the same effects
  244.  * as function keys.  The only way to get into this code, however, is to
  245.  * have something produce debug output in the first place!  This is
  246.  * awkward: Hit a key on out_device, then hit ctl-alt-F5 on the console so
  247.  * bios.c will call DUMPPROC, which will call ALERT, which will call this.
  248.  * It'll see the key you hit on out_device and drop you into this loop.
  249.  * CTL-ALT keys make BIOS call do_func_key even when out_device isn't the
  250.  * console.
  251.  */
  252.  
  253. void
  254. debug_ws(s)
  255.     const char *s;
  256. {
  257.     long key;
  258.     int scan;
  259.     int stopped;
  260.  
  261.     while (*s) {
  262.     (void)Bconout(out_device, *s);
  263.     while (*s == '\n' && out_device != 0 && Bconstat(out_device)) {
  264.         stopped = 0;
  265.         while (1) {
  266.         /* got a key; if ctl-alt then do it */
  267.         key = Bconin(out_device);
  268.         if (out_device == 2) {
  269.             if ((Kbshift(-1) & 0x0c) == 0x0c) {
  270.             scan = ((key >> 16) & 0xff);
  271.             do_func_key(scan);
  272.             }
  273.             else goto ptoggle;
  274.         }
  275.         else {
  276.             if (key < '0' || key > '9') {
  277. ptoggle:        /* not a func key */
  278.             if (stopped) break;
  279.             else stopped = 1;
  280.             }
  281.             else {
  282.             /* digit key from debug device == Fn */
  283.             if (key == '0') scan = 0x44;
  284.             else scan = key - '0' + 0x3a;
  285.             do_func_key(scan);
  286.             }
  287.         }
  288.         }
  289.     }
  290.     s++;
  291.     }
  292. }
  293.  
  294. /*
  295.  * _ALERT(s) returns 1 for success and 0 for failure.
  296.  * It attempts to write the string to "the alert pipe," u:\pipe\alert.
  297.  * If the write fails because the pipe is full, we "succeed" anyway.
  298.  *
  299.  * This is called in vdebugout and also in memprot.c for memory violations.
  300.  * It's also used by the Salert() system call in dos.c.
  301.  */
  302.  
  303. int
  304. _ALERT(s)
  305. char *s;
  306. {
  307.     FILEPTR *f;
  308.     char alertbuf[SPRINTF_MAX+10], *ptr, *lastspace;
  309.     int counter;
  310.     char *alert;
  311.     int olddebug = debug_level;
  312.     int oldlogging = debug_logging;
  313.  
  314. /* temporarily reduce the debug level, so errors finding
  315.  * u:\pipe\alert don't get reported
  316.  */
  317.     debug_level = debug_logging = 0;
  318.     f = do_open("u:\\pipe\\alert",(O_WRONLY | O_NDELAY),0,(XATTR *)0);
  319.     debug_level = olddebug;
  320.     debug_logging = oldlogging;
  321.  
  322.     if (f) {
  323. /*
  324.  * format the string into an alert box
  325.  */
  326.     if (*s == '[') {    /* already an alert */
  327.         alert = s;
  328.     } else {
  329.         alert = alertbuf;
  330.         ksprintf(alertbuf, "[1][%s", s);
  331. /*
  332.  * make sure no lines exceed 30 characters; also, filter out any
  333.  * reserved characters like '[' or ']'
  334.  */
  335.         ptr = alertbuf+4;
  336.         counter = 0;
  337.         lastspace = 0;
  338.         while(*ptr) {
  339.             if (*ptr == ' ') {
  340.                 lastspace = ptr;
  341.             } else if (*ptr == '[') {
  342.                 *ptr = '(';
  343.             } else if (*ptr == ']') {
  344.                 *ptr = ')';
  345.             } else if (*ptr == '|') {
  346.                 *ptr = ':';
  347.             }
  348.             if (counter++ >= 29) {
  349.                 if (lastspace) {
  350.                     *lastspace = '|';
  351.                     counter = ptr - lastspace;
  352.                     lastspace = 0;
  353.                 } else {
  354.                     *ptr = '|';
  355.                     counter = 0;
  356.                 }
  357.             }
  358.             ptr++;
  359.         }
  360.         strcpy(ptr, "][  OK  ]");
  361.     }
  362.  
  363.     (*f->dev->write)(f,alert,(long)strlen(alert)+1);
  364.     do_close(f);
  365.     return 1;
  366.     }
  367.     else return 0;
  368. }
  369.  
  370. static void
  371. VDEBUGOUT(level, s, args)
  372.     int level;
  373.     const char *s;
  374.     va_list args;
  375. {
  376.     char *lp;
  377.     char *lptemp;
  378.  
  379.     logtime[logptr] = (short)(*(long *)0x4baL);
  380.     lp = logbuf[logptr];
  381.     if (++logptr == LBSIZE) logptr = 0;
  382.  
  383.     if (curproc) {
  384.         ksprintf(lp,"pid %3d (%s): ", curproc->pid, curproc->name);
  385.         lptemp = lp+strlen(lp);
  386.     }
  387.     else {
  388.         lptemp = lp;
  389.     }
  390.  
  391.     vksprintf(lptemp, s, args);
  392.  
  393.     /* for alerts, try the alert pipe unconditionally */
  394.     if (level == ALERT_LEVEL && _ALERT(lp)) return;
  395.  
  396.     if (debug_level >= level) {
  397.         debug_ws(lp);
  398.         debug_ws("\r\n");
  399.     }
  400. }
  401.  
  402. void ARGS_ON_STACK Tracelow(const char *s, ...)
  403. {
  404.     va_list args;
  405.  
  406.     if (debug_logging || (debug_level >= LOW_LEVEL)) {
  407.         va_start(args, s);
  408.         VDEBUGOUT(LOW_LEVEL, s, args);
  409.         va_end(args);
  410.     }
  411. }
  412.  
  413. void ARGS_ON_STACK Trace(const char *s, ...)
  414. {
  415.     va_list args;
  416.  
  417.     if (debug_logging || (debug_level >= TRACE_LEVEL)) {
  418.         va_start(args, s);
  419.         VDEBUGOUT(TRACE_LEVEL, s, args);
  420.         va_end(args);
  421.     }
  422. }
  423.  
  424. void ARGS_ON_STACK Debug(const char *s, ...)
  425. {
  426.     va_list args;
  427.  
  428.     if (debug_logging || (debug_level >= DEBUG_LEVEL)) {
  429.         va_start(args, s);
  430.         VDEBUGOUT(DEBUG_LEVEL, s, args);
  431.         va_end(args);
  432.     }
  433.     if (debug_logging && debug_level >= DEBUG_LEVEL) DUMPLOG();
  434. }
  435.  
  436. void ARGS_ON_STACK ALERT(const char *s, ...)
  437. {
  438.     va_list args;
  439.  
  440.     if (debug_logging || debug_level >= ALERT_LEVEL) {
  441.         va_start(args, s);
  442.         VDEBUGOUT(ALERT_LEVEL, s, args);
  443.         va_end(args);
  444.     }
  445.     if (debug_logging && debug_level >= ALERT_LEVEL) DUMPLOG();
  446. }
  447.  
  448. void ARGS_ON_STACK FORCE(const char *s, ...)
  449. {
  450.     va_list args;
  451.  
  452.     va_start(args, s);
  453.     VDEBUGOUT(FORCE_LEVEL, s, args);
  454.     va_end(args);
  455.     /* don't dump log here - hardly ever what you mean to do. */
  456. }
  457.  
  458. void
  459. DUMPLOG()
  460. {
  461.     char *end;
  462.     char *start;
  463.     short *timeptr;
  464.     char timebuf[6];
  465.  
  466.     /* logbuf[logptr] is the oldest string here */
  467.  
  468.     end = start = logbuf[logptr];
  469.     timeptr = &logtime[logptr];
  470.  
  471.     do {
  472.         if (*start) {
  473.         ksprintf(timebuf,"%04x ",*timeptr);
  474.         debug_ws(timebuf);
  475.         debug_ws(start);
  476.         debug_ws("\r\n");
  477.         *start = '\0';
  478.         }
  479.         start += LB_LINE_LEN;
  480.         timeptr++;
  481.         if (start == logbuf[LBSIZE]) {
  482.         start = logbuf[0];
  483.         timeptr = &logtime[0];
  484.         }
  485.         } while (start != end);
  486.  
  487.         logptr = 0;
  488. }
  489.  
  490. /* wait for a key to be pressed */
  491. void
  492. PAUSE()
  493. {
  494.     debug_ws("Hit a key\r\n");
  495.     (void)Bconin(2);
  496. }
  497.   
  498. EXITING
  499. void ARGS_ON_STACK FATAL(const char *s, ...)
  500. {
  501.     va_list args;
  502.  
  503.     va_start(args, s);
  504.     VDEBUGOUT(-1, s, args);
  505.     va_end(args);
  506.     if (debug_logging) {
  507.         DUMPLOG();
  508.     }
  509.  
  510.     HALT();
  511. }
  512.  
  513.  
  514. EXITING 
  515. void HALT()
  516. {
  517.     long r;
  518.     long key;
  519.     int scan;
  520.     extern long tosssp;    /* in main.c */
  521. #ifdef PROFILING
  522.     extern EXITING _exit P_((int));
  523. #endif
  524.     restr_intr();    /* restore interrupts to normal */
  525.     debug_ws("Fatal MiNT error: adjust debug level and hit a key...\r\n");
  526.     sys_q[READY_Q] = 0;    /* prevent context switches */
  527.  
  528.     for(;;) {
  529.         /* get a key; if ctl-alt then do it, else halt */
  530.         key = Bconin(out_device);
  531.         if ((key & 0x0c000000) == 0x0c000000) {
  532.             scan = ((key >> 16) & 0xff);
  533.             do_func_key(scan);
  534.         }
  535.         else {
  536.             break;
  537.         }
  538.     }
  539.     for(;;) {
  540.     debug_ws("System halted. Press 'x' to exit, or else reboot\r\n");
  541.         r = Bconin(2);
  542.  
  543.         if ( (r & 0x0ff) == 'x' ) {
  544.             close_filesys();
  545.             (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  546. #ifdef PROFILING
  547.             _exit(0);
  548. #else
  549.             Pterm0();
  550. #endif
  551.         }
  552.     }
  553. }
  554.  
  555.  
  556. /* some key definitions */
  557. #define CTRLALT 0xc
  558. #define DEL 0x53    /* scan code of delete key */
  559. #define UNDO 0x61    /* scan code of undo key */
  560.  
  561. void
  562. do_func_key(scan)
  563.     int scan;
  564. {
  565.     extern struct tty con_tty;
  566.  
  567.     switch (scan) {
  568.     case DEL:
  569.         reboot();
  570.         break;
  571.     case UNDO:
  572.         killgroup(con_tty.pgrp, SIGQUIT);
  573.         break;
  574. #ifndef NO_DEBUG_INFO
  575.     case 0x3b:        /* F1: increase debugging level */
  576.         debug_level++;
  577.         break;
  578.     case 0x3c:        /* F2: reduce debugging level */
  579.         if (debug_level > 0)
  580.             --debug_level;
  581.         break;
  582.     case 0x3d:        /* F3: cycle out_device */
  583.         out_device = out_next[out_device];
  584.         break;
  585.     case 0x3e:        /* F4: set out_device to console */
  586.         out_device = 2;
  587.         break;
  588.     case 0x3f:        /* F5: dump memory */
  589.         DUMPMEM(ker);
  590.         DUMPMEM(core);
  591.         DUMPMEM(alt);
  592.         break;
  593.     case 0x40:        /* F6: dump processes */
  594.         DUMPPROC();
  595.         break;
  596.     case 0x41:        /* F7: toggle debug_logging */
  597.         debug_logging ^= 1;
  598.         break;
  599.     case 0x42:        /* F8: dump log */
  600.         DUMPLOG();
  601.         break;
  602.     case 0x43:        /* F9: dump the global memory table */
  603.         QUICKDUMP();
  604.         break;
  605.     case 0x5c:        /* shift-F9: dump the mmu tree */
  606.         BIG_MEM_DUMP(1,curproc);
  607.         break;
  608.     case 0x44:        /* F10: do an annotated dump of memory */
  609.         BIG_MEM_DUMP(0,0);
  610.         break;
  611. #endif
  612.     }
  613. }
  614.